﻿# Copyright (C) 2009 Martin Kirsche

import hashlib
import urllib2
from xml.etree import ElementTree


class LastFmClient(object):

    handshakeUrl = 'http://ws.audioscrobbler.com/radio/handshake.php?version=1.3.2.13&platform=win32&username=%s&passwordmd5=%s&language=%s&player=winamp'
    adjustUrl = 'http://ws.audioscrobbler.com/radio/adjust.php?session=%s&url=%s&lang=%s'
    playListUrl = 'http://ws.audioscrobbler.com/radio/xspf.php?sk=%s&discovery=0&desktop=1.3.2.13'
    language = 'en'
    session = None
    user = None
    password = None
    stationName = None
    stationUrl = None

    def handshake(self, user = None, password = None):
        if user:
            self.user = user
        if password:
            self.password = password
        self.stationName = None
        self.session = None
        resp = parse_key_value(urllib2.urlopen(self.handshakeUrl % (self.user, hashlib.md5(self.password).hexdigest(), self.language)).read())
        self.session = resp['session']
        if self.session == 'FAILED':
            self.session = None
            raise LastFmClientError('Creating session failed.')
        if self.stationUrl:
            self.adjust()
        return resp

    def adjust(self, stationUrl = None):
        if stationUrl:
            self.stationUrl = stationUrl
        if not self.stationUrl:
            return
        self.check_session()
        resp = parse_key_value(urllib2.urlopen(self.adjustUrl % (self.session, self.stationUrl, self.language)).read())
        if resp.has_key('ERROR'):
            self.session = None
            raise LastFmClientError(resp['ERROR'])
        if not resp.has_key('response'):
            self.session = None
            raise LastFmClientError('Unable to parse the response.')
        if resp['response'] != 'OK':
            self.session = None
            raise LastFmClientError('Adjustion failed.')
        self.stationName = resp['stationname']
        return self.stationName

    def playlist(self):
        self.check_session()
        try:
            return parse_playlist(urllib2.urlopen(self.playListUrl % (self.session)).read())
        except urllib2.HTTPError:
            self.session = None
            raise

    def check_session(self):
        if not self.session:
            self.handshake()
            if not self.session:
                raise LastFmClientError('Creating session failed.')


def parse_playlist(xmlText, id=0):
    trackList = []
    root = ElementTree.XML(xmlText)
    for t in root.findall('trackList/track'):
        trackList.append(Track(
            id,
            t.findtext('creator',None),
            t.findtext('album',None),
            t.findtext('title',None),
            t.findtext('duration',None),
            t.findtext('location',None),
            t.findtext('image',None)))
        id = id + 1
    return trackList


def parse_key_value(text):
    dict = {}
    for line in text.splitlines():
        kvp = line.partition('=')
        dict[kvp[0]]=kvp[2]
    return dict

    
class Track(object):
    
    def __init__(self, id, creator, album, title, duration, location, image = None):
        self.id = id
        self.creator = creator
        self.album = album
        self.title = title
        self.duration = duration
        self.location = location
        self.image = image


class LastFmClientError(Exception):
    
    def __init__(self, value):
        self.value = value
    
    def __str__(self):
        return repr(self.value)
